package model

import (
	"fmt"
	"github.com/go-xorm/xorm"
	"time"
	"global/structs"
	"github.com/shopspring/decimal"
)

const DEFAULT_OFFICIAL_UID = 1000000

type UserCoin struct {
	Id               int
	Uid              int
	Coin             string
	Balance          string
	BalanceAvailable string
	BalanceLock      string
	CreateTime       time.Time
	UpdateTime       time.Time
}

type userCoin struct{}

var UserCoinModel = new(userCoin)

func getTableName(coinType string) string {
	return fmt.Sprintf("user_coin_%s", coinType)
}

// 添加排他锁
func (self userCoin) GetItemWithLock(sess *xorm.Session, uid int, coinType string) (*structs.UserCoinBalance, error) {
	userCoinItem, err := self.getItem(sess, uid, coinType)
	if err != nil {
		return nil, err
	}
	if userCoinItem == nil {
		yes, err := self.createDefaultUserCoin(sess, coinType, uid)
		if err != nil || !yes{
			return nil, err
		}

		userCoinItem, err = self.getItem(sess, uid, coinType)
		if err != nil {
			return nil, err
		}
	}
	return &structs.UserCoinBalance{
		Id: 				userCoinItem.Id,
		Balance:			userCoinItem.Balance,
		BalanceAvailable: 	userCoinItem.BalanceAvailable,
		BalanceLock: 		userCoinItem.BalanceLock,
	}, nil
}

// 获取用户资产
func (userCoin) getItem(sess *xorm.Session, uid int, coinType string) (*UserCoin, error) {
	var userCoin UserCoin
	has, err := sess.Table("user_coin_" + coinType).Where("uid=?", uid).ForUpdate().Get(&userCoin)
	if err != nil {
		return nil, err
	}
	if has {
		return &userCoin, nil
	}
	return nil, nil
}

func (userCoin) createDefaultUserCoin(sess *xorm.Session, coinType string, uid int) (bool, error) {
	zero := decimal.Zero.StringFixed(16)
	userCoin := &UserCoin{
		Uid: 				uid,
		Coin: 				coinType,
		Balance: 			zero,
		BalanceAvailable:	zero,
		BalanceLock: 		zero,
		CreateTime: 		time.Now(),
		UpdateTime: 		time.Now(),
	}
	var err error
	// 尝试创建5次
	for i:=0; i<5; i++ {
		affected, err := sess.Table("user_coin_" + coinType).Insert(userCoin)
		if err != nil {
			continue
		}
		if affected > 0 {
			return true, nil
		}
	}
	return false, err
}

// 修改余额
func (userCoin) UpdateBalanceBuySQL(sess *xorm.Session, uid int, number, coin string) (bool, error) {

	sql := fmt.Sprintf("UPDATE `user_coin_%s` SET `balance`=`balance`+'%s', `balance_available`=`balance_available`+'%s', update_time='%s' WHERE uid=%d",
		coin, number, number, time.Now().Format("2006-01-02 15:04:05"), uid)
	res, err := sess.Exec(sql)
	if err != nil {
		return false, err
	}
	if res != nil {
		rows, err := res.RowsAffected()
		if err != nil {
			return false, err
		}
		return rows > 0, nil
	}
	return false, fmt.Errorf("update user balance error, msg: %s", err.Error())
}

// 获取记录
func (userCoin) Get(uid int, coinType string) *UserCoin {
	item := new(UserCoin)
	_, err := MainDB.Table(getTableName(coinType)).Where("uid=?", uid).Get(item)
	if err != nil {
		return nil
	}
	return item
}

// 更新
func (userCoin) Update(session *xorm.Session, id int, coinType, balance, available, lock string) (bool, error) {
	affected, err := session.Table(getTableName(coinType)).
		Where("id=?", id).
		Cols("balance", "balance_available", "balance_lock", "update_time").
		Update(&UserCoin{
			Balance:          balance,
			BalanceAvailable: available,
			BalanceLock:      lock,
			UpdateTime:       time.Now(),
		})
	if err == nil && affected > 0 {
		return true, nil
	}
	return false, err
}
